/**
 * @file main.c
 * @author lcz (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2022-1-7
 *
 * @copyright Copyright (c) 2022
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
// 本节对应语法分析 语句的处理7-8表达式得处理
// 解决类型的强制转换问题
//
// #define int long long

// 当前的token
int token;
int token_val;   // value of current token (mainly for number)
int *current_id, // current parsed ID , tokenId
    *symbols;    // symbol table    符号表

// 全局变量 方便使用
int basetype;  // the type of a declaration, make it global for convenience  设置成全局的变量比较方便
int expr_type; // the type of an expression

int index_of_bp; // index of bp pointer on stack 全局变量 在函数调用的时候指向bp寄存器

// types of variable/function
// 变量或函数的类型 PTR指针吗？？
enum
{
    CHAR,
    INT,
    PTR
};
int *idmain; // the `main` function

// fields of identifier
// 符号表的字段
enum
{
    Token,  // 该标识符返回的标记，理论上所有的变量返回的标记都应该是 Id，但实际上由于我们还将在符号表中加入关键字如 if, while 等，它们都有对应的标记。
    Hash,   // 顾名思义，就是这个标识符的哈希值，用于标识符的快速比较。
    Name,   // 存放标识符本身的字符串。
    Type,   // 该标识符的类别，如数字，全局变量或局部变量等。
    Class,  // 标识符的类型，即如果它是个变量，变量是 int 型、char 型还是指针型。
    Value,  // 存放这个标识符的值，如标识符是函数，刚存放函数的地址。
    BType,  // BXXX: C 语言中标识符可以是全局的也可以是局部的，当局部标识符的名字与全局标识符相同时，用作保存全局标识符的信息。
    BClass, //
    BValue, //
    IdSize  //
};

// 指向源代码的指针
char *src, *old_src;
// 文件缓冲区大小
int poolSize;
// 当前行
int line;

int *text;     // 代码段
int *old_text; // 重复的代码段
int *stack;    // 栈
char *data;    // 数据段，我们的数据只有字符串
// 虚拟机中的寄存器
int *pc, *bp, *sp, ax, cycle;

// instructions
// 定义虚拟机的指令集
enum
{
    LEA,  // 根据参数获取地址
    IMM,  // 将num（param）放到ax
    JMP,  // 跳转指令
    CALL, // 函数调用指令
    JZ,   // 等于零跳转
    JNZ,  // 不等于跳转
    ENT,  // 子程序进入指令， 该指令进行子函数调用前的预操作
    ADJ,  // 将调用子函数时压入栈中的数据清除
    LEV,  // 恢复sp 弹栈恢复bp 替代ret 进行函数调用返回
    LI,   // 指定地址字符放ax中，ax原来放地址
    LC,   // 指定地址整数放ax中，ax原来放地址
    SI,   // ax中数据以字符放指定地址，栈顶放目标地址
    SC,   // ax中数据以整数放指定地址，栈顶放目标地址
    PUSH, // 压栈 先--后赋值
    // 算数运算算操作数 第一操作数在栈顶 第二操作数在ax中 运算结果放ax中，栈顶弹出
    OR,   // 或
    XOR,  // 异或
    AND,  // 与
    EQ,   // 等值判断==
    NE,   // 不等值判断！=
    LT,   // 小于
    GT,   // 大于
    LE,   // 小于等于
    GE,   // 大于等于
    SHL,  // 左移
    SHR,  // 右移
    ADD,  // 加
    SUB,  // 减
    MUL,  // 乘
    DIV,  // 除
    MOD,  // 取模
    OPEN, // 打开文件
    READ, // 读取文件
    CLOS, // 关闭文件
    PRTF, //
    MALC,
    MSET,
    MCMP, // 比较
    EXIT  // 退出（此时放回栈顶数值）

};

// 支持的标记
// tokens and classes (operators last and in precedence order)
enum
{
    // 128 ASCII码部分重叠
    Num = 128,
    Fun, // 函数
    Sys, // 系统函数
    Glo, // 全局
    Loc, // 本地
    Id,
    Char,
    Else,
    Enum,
    If,
    Int,
    Return,
    Sizeof,
    While,
    Assign, //= 赋值语句
    Cond,   // ？
    Lor,    // 长或||
    Lan,    // 长与&&
    Or,
    Xor, // 异或
    And,
    Eq,
    Ne,
    Lt,
    Gt,
    Le,
    Ge,
    Shl,
    Shr,
    Add,
    Sub,
    Mul,
    Div,
    Mod,
    Inc, //++
    Dec, //--
    Brak //[
};

void expression(int level);

/**
 * @brief 获取下一各token
 *
 */
void next()
{
    // 指向一个token单词的第一个一个 字母 例如对于while 指向w
    char *last_pos;
    int hash;

    while (token = *src)
    {
        ++src;
        // parse token here
        // 处理换行符
        if (token == '\n')
        {
            ++line;
        }
        // 处理宏定义 处理即是跳过宏定义
        else if (token == '#')
        {
            // skip macro, because we will not support it
            while (*src != 0 && *src != '\n')
            {
                src++;
            }
        }
        // 处理标识符 标识符已字母下划线开头
        else if ((token >= 'a' && token <= 'z') || (token >= 'A' && token <= 'Z') || (token == '_'))
        {

            // parse identifier
            last_pos = src - 1;
            hash = token;

            while ((*src >= 'a' && *src <= 'z') || (*src >= 'A' && *src <= 'Z') || (*src >= '0' && *src <= '9') || (*src == '_'))
            {
                // 计算hash值
                hash = hash * 147 + *src;
                src++;
            }

            // look for existing identifier, linear search
            // 在调用parse前，我们的关键字已经全部安排到符号表了，ok的!
            // 获取符号表指针
            current_id = symbols;
            while (current_id[Token])
            {
                if (current_id[Hash] == hash && !memcmp((char *)current_id[Name], last_pos, src - last_pos))
                {
                    // found one, return
                    token = current_id[Token];
                    return;
                }
                // 一个关键字或变量名在符号表占用9各位，每个位大小相同，这里切换到下一个符号处
                current_id = current_id + IdSize;
            }

            // store new ID
            // 在语法层面解析变量的作用
            // 变量的Token取值统一时Id 而token变量也取该变量
            current_id[Name] = (int)last_pos;
            current_id[Hash] = hash;
            token = current_id[Token] = Id;
            return;
        }
        // 处理数字
        // 将数字值存放在token_val中，无论该值是自变量还是字面量
        else if (token >= '0' && token <= '9')
        {
            // parse number, three kinds: dec(123) hex(0x123) oct(017)
            token_val = token - '0';
            if (token_val > 0)
            {
                // dec, starts with [1-9]
                // 解析 10进制数值
                while (*src >= '0' && *src <= '9')
                {
                    token_val = token_val * 10 + *src++ - '0';
                }
            }
            else
            {
                // starts with number 0
                // 解析8或16进制
                if (*src == 'x' || *src == 'X')
                {
                    // hex
                    //  16
                    //  token为16进制的第一个数
                    token = *++src;

                    while ((token >= '0' && token <= '9') || (token >= 'a' && token <= 'f') || (token >= 'A' && token <= 'F'))
                    {
                        // a 0110 0001  97
                        // A 0100 0001  65
                        // 1 0011 0001  49
                        //  (token & 15) 获取各位 对于a-f 或 A-F 个位为1-6 数值0-9 对应0-9
                        // 若为a-f or A-F 补上缺少的9
                        token_val = token_val * 16 + (token & 15) + (token >= 'A' ? 9 : 0);
                        token = *++src;
                    }
                }
                else
                {
                    // oct
                    while (*src >= '0' && *src <= '7')
                    {
                        //
                        token_val = token_val * 8 + *src++ - '0';
                    }
                }
            }

            token = Num;
            return;
        }
        else if (token == '"' || token == '\'')
        {
            // 解析字符串文本 当前仅支持空格（按空格进行解析）
            // parse string literal, currently, the only supported escape
            // character is '\n', store the string literal into data.
            // last_pos 指向data数据区域
            last_pos = data;
            // 进入while循环时 token=“ 或 \' src等于“时字符串结束
            while (*src != 0 && *src != token)
            {
                token_val = *src++;
                if (token_val == '\\')
                {
                    // escape character
                    token_val = *src++;
                    if (token_val == 'n')
                    {
                        token_val = '\n';
                    }
                }
                // 如果token是” 代表现在读取的是一个字符串
                if (token == '"')
                {
                    // 将token_val的值（字符串的每个值，不断的拷贝到data区域）
                    *data++ = token_val;
                }
            }
            // 字符串拷贝结束 src++
            src++;
            // if it is a single character, return Num token
            // 处理单个字符，好吧！这里不是很懂哦！
            if (token == '"')
            {
                token_val = (int)last_pos;
            }
            else
            {
                token = Num;
            }

            return;
        }
        else if (token == '/')
        {
            if (*src == '/')
            {
                // skip comments
                while (*src != 0 && *src != '\n')
                {
                    ++src;
                }
            }
            else
            {
                // divide operator
                token = Div;
                return;
            }
        }
        else if (token == '=')
        {
            // parse '==' and '='
            if (*src == '=')
            {
                src++;
                token = Eq;
            }
            else
            {
                token = Assign;
            }
            return;
        }
        else if (token == '+')
        {
            // parse '+' and '++'
            if (*src == '+')
            {
                src++;
                token = Inc;
            }
            else
            {
                token = Add;
            }
            return;
        }
        else if (token == '-')
        {
            // parse '-' and '--'
            if (*src == '-')
            {
                src++;
                token = Dec;
            }
            else
            {
                token = Sub;
            }
            return;
        }
        else if (token == '!')
        {
            // parse '!='
            if (*src == '=')
            {
                src++;
                token = Ne;
            }
            return;
        }
        else if (token == '<')
        {
            // parse '<=', '<<' or '<'
            if (*src == '=')
            {
                src++;
                token = Le;
            }
            else if (*src == '<')
            {
                src++;
                token = Shl;
            }
            else
            {
                token = Lt;
            }
            return;
        }
        else if (token == '>')
        {
            // parse '>=', '>>' or '>'
            if (*src == '=')
            {
                src++;
                token = Ge;
            }
            else if (*src == '>')
            {
                src++;
                token = Shr;
            }
            else
            {
                token = Gt;
            }
            return;
        }
        else if (token == '|')
        {
            // parse '|' or '||'
            if (*src == '|')
            {
                src++;
                token = Lor;
            }
            else
            {
                token = Or;
            }
            return;
        }
        else if (token == '&')
        {
            // parse '&' and '&&'
            if (*src == '&')
            {
                src++;
                token = Lan;
            }
            else
            {
                token = And;
            }
            return;
        }
        else if (token == '^')
        {
            token = Xor;
            return;
        }
        else if (token == '%')
        {
            token = Mod;
            return;
        }
        else if (token == '*')
        {
            token = Mul;
            return;
        }
        else if (token == '[')
        {
            token = Brak;
            return;
        }
        else if (token == '?')
        {
            token = Cond;
            return;
        }
        // 以下的符号 直接返回token当标识符
        else if (token == '~' || token == ';' || token == '{' || token == '}' || token == '(' || token == ')' || token == ']' || token == ',' || token == ':')
        {
            // directly return the character as token;
            return;
        }
    }
    return;
}

void match(int tk)
{
    if (token == tk)
    {
        next();
    }
    else
    {
        printf("%d: expected token: %d\n", line, tk);
        exit(-1);
    }
}

void enum_declaration()
{
    // parse enum [id] { a = 1, b = 3, ...}
    int i;
    i = 0;
    while (token != '}')
    {
        if (token != Id)
        {
            printf("%d: bad enum identifier %d\n", line, token);
            exit(-1);
        }
        next();
        if (token == Assign)
        {
            // like {a=10}
            next();
            if (token != Num)
            {
                printf("%d: bad enum initializer\n", line);
                exit(-1);
            }
            i = token_val;
            next();
        }

        current_id[Class] = Num;
        current_id[Type] = INT;
        current_id[Value] = i++;

        if (token == ',')
        {
            next();
        }
    }
}
void function_parameter()
{
    int type;
    int params;
    // 记录参数个数
    params = 0;
    // 循环解析参数
    while (token != ')')
    {
        // ①

        // int name, ...
        // 获取参数类型
        type = INT;
        if (token == Int)
        {
            match(Int);
        }
        else if (token == Char)
        {
            type = CHAR;
            match(Char);
        }

        // pointer type
        // 判断类型是否是指针
        while (token == Mul)
        {
            match(Mul);
            type = type + PTR;
        }

        // parameter name
        // 获取参数名称
        if (token != Id)
        {
            printf("%d: bad parameter declaration\n", line);
            exit(-1);
        }
        // 如果存在同名的参数 那门解析失败
        if (current_id[Class] == Loc)
        {
            printf("%d: duplicate parameter declaration\n", line);
            exit(-1);
        }

        // 匹配参数
        // 再读取token的时候 及是调用next函数的过程中便将标识符的解百纳信息写入符号表中了
        match(Id);

        // ②
        //  store the local variable
        //  将全局变量进行覆盖
        current_id[BClass] = current_id[Class];
        current_id[Class] = Loc;
        current_id[BType] = current_id[Type];
        current_id[Type] = type;
        current_id[BValue] = current_id[Value];
        current_id[Value] = params++; // index of current parameter

        // 匹配逗号
        if (token == ',')
        {
            match(',');
        }
    }

    // ③
    // 设置bp 一个参数放一个bp处嘛 index_of_bp 指向
    index_of_bp = params + 1;
}

void statement()
{
    // there are 6 kinds of statements here:
    // 1. if (...) <statement> [else <statement>]
    // 2. while (...) <statement>
    // 3. { <statement> }
    // 4. return xxx;
    // 5. <empty statement>;
    // 6. expression; (expression end with semicolon)
    int *a, *b; // bess for branch control
    if (token == If)
    {
        match(If);
        match('(');
        expression(Assign); // parse condition
        match(')');
        // 汇编代码 ax为0 b为（条件false部分语句）
        *++text = JZ;
        // 需要回填的else的地址后if结束的地址
        b = ++text;

        statement(); // parse statement
        if (token == Else)
        { // parse else
            match(Else);

            // emit code for JMP B
            *b = (int)(text + 3); //  填写else语句的地址
            *++text = JMP;        // 填写true条件下的跳出语句地址
            b = ++text;           // 跳出，填写true条件下的跳出语句地址
            // 3 else语句的地址
            // 2 jmp
            // 1 b
            // 处理完else部分语句
            statement();
        }
        // if语句的后面语句 1）如果else存在 汇编true条件下的jmp指令（true指令运行完后跳过else部分语句）
        // 2）else不存在 回填判断的false语句部分
        *b = (int)(text + 1);
    }
    else if (token == While)
    {
        match(While);
        // 获取while循环的首语句地址 包括判断条件包含在内
        a = text + 1;

        match('(');
        // 表达式 判断条件部分的地址
        expression(Assign);
        match(')');
        // b地址为退出循环的地址 需要回填
        *++text = JZ; // 等于0不满住while跳出循环
        b = ++text;
        // while语句代码生成
        statement();

        // 语句处理完了 进行无条件的跳回while循环的首部
        *++text = JMP;
        // 无条件跳回a 且回填b
        *++text = (int)a;
        *b = (int)(text + 1);
    }
    else if (token == Return)
    {
        // return [expression];
        match(Return);

        if (token != ';')
        {
            expression(Assign);
        }

        match(';');

        // emit code for return
        *++text = LEV;
    }
    else if (token == '{')
    {
        // { <statement> ... }
        match('{');

        while (token != '}')
        {
            statement();
        }

        match('}');
    }
    else if (token == ';')
    {
        // empty statement
        match(';');
    }
    else
    {
        // a = b; or function_call();
        expression(Assign);
        match(';');
    }
}

void function_body()
{
    // type func_name (...) {...}
    //                   -->|   |<--

    // ... {
    // 1. local declarations
    // 2. statements
    // }

    int pos_local; // position of local variables on the stack.
    int type;
    pos_local = index_of_bp;

    // ①
    while (token == Int || token == Char)
    {
        // local variable declaration, just like global ones.
        basetype = (token == Int) ? INT : CHAR;
        match(token);

        while (token != ';')
        {
            type = basetype;
            while (token == Mul)
            {
                match(Mul);
                type = type + PTR;
            }

            if (token != Id)
            {
                // invalid declaration
                printf("%d: bad local declaration\n", line);
                exit(-1);
            }
            if (current_id[Class] == Loc)
            {
                // identifier exists
                printf("%d: duplicate local declaration\n", line);
                exit(-1);
            }
            match(Id);

            // store the local variable
            current_id[BClass] = current_id[Class];
            current_id[Class] = Loc;
            current_id[BType] = current_id[Type];
            current_id[Type] = type;
            current_id[BValue] = current_id[Value];
            current_id[Value] = ++pos_local; // index of current parameter

            if (token == ',')
            {
                match(',');
            }
        }
        match(';');
    }

    // ②
    // save the stack size for local variables
    *++text = ENT;
    *++text = pos_local - index_of_bp;

    // statements
    while (token != '}')
    {
        statement();
    }

    // emit code for leaving the sub function
    *++text = LEV;
}

void function_declaration()
{
    // type func_name (...) {...}
    //               | this part

    match('(');
    // 完成（读取后读取参数
    function_parameter();
    match(')');
    match('{');
    // 读取函数的body
    function_body();
    // match('}');                 //  ①

    // ②
    // unwind local variable declarations for all local variables.
    current_id = symbols;
    while (current_id[Token])
    {
        // 全局变量的覆盖 再function1body中进行了覆盖，现在完成了函数的翻译，恢复覆盖的全局变量
        if (current_id[Class] == Loc)
        {
            current_id[Class] = current_id[BClass];
            current_id[Type] = current_id[BType];
            current_id[Value] = current_id[BValue];
        }
        current_id = current_id + IdSize;
    }
}

/**
 * @brief 全局声明
 *
 */
void global_declaration()
{
    // global_declaration ::= enum_decl | variable_decl | function_decl
    //
    // enum_decl ::= 'enum' [id] '{' id ['=' 'num'] {',' id ['=' 'num'} '}'
    //
    // variable_decl ::= type {'*'} id { ',' {'*'} id } ';'
    //
    // function_decl ::= type {'*'} id '(' parameter_decl ')' '{' body_decl '}'

    int type; // tmp, actual type for variable
    int i;    // tmp

    basetype = INT;

    // parse enum, this should be treated alone.
    // 枚举变量需要独自对待
    if (token == Enum)
    {
        // enum [id] { a = 10, b = 20, ... }
        match(Enum);
        if (token != '{')
        {
            match(Id); // skip the [id] part
            // 有Id我们也跳过 我们直接编译变量，所以问题不大
        }
        if (token == '{')
        {
            // parse the assign part
            match('{');
            enum_declaration();
            match('}');
        }

        match(';');
        return;
    }

    // parse type information
    // 不是enum开头，是一个函数声明或变量声明
    if (token == Int)
    {
        match(Int);
    }
    else if (token == Char)
    {
        match(Char);
        basetype = CHAR;
    }

    // parse the comma seperated variable declaration.
    // 解析逗号分隔的变量声明。
    // ; 为变量声明的结束符 }为函数声明的结束符
    while (token != ';' && token != '}')
    {
        type = basetype;
        // parse pointer type, note that there may exist `int ****x;`
        // 变量或函数的基础类型确定了后就确定是否是指针
        while (token == Mul)
        {
            match(Mul);
            type = type + PTR;
        }

        // 处理如果变量或函数缺乏名称
        if (token != Id)
        {
            // invalid declaration
            printf("%d: bad global declaration\n", line);
            exit(-1);
        }
        if (current_id[Class])
        {
            // identifier exists
            // id存在则报错 不可重复定义
            printf("%d: duplicate global declaration\n", line);
            exit(-1);
        }
        // 匹配ID 函数名或变量名
        match(Id);
        // 类型设置
        current_id[Type] = type;
        // 函数处理
        if (token == '(')
        {
            current_id[Class] = Fun;
            // 函数的符号表的值指向写一个地址，及将下面的地址取值放符号表值
            current_id[Value] = (int)(text + 1); // the memory address of function
            // 处理函数声明
            function_declaration();
        }
        else
        {
            // variable declaration
            // 变量声明
            current_id[Class] = Glo; // global variable
            // 变量值 指向一个类型空间
            current_id[Value] = (int)data; // assign memory address
            data = data + sizeof(int);
            // 修改data指针 跳过这部分地址
        }
        // 处理变量声明的其余部分
        if (token == ',')
        {
            match(',');
        }
    }
    next();
}

/**
 * @brief 计算表达式
 *
 * @param level
 * @return * void
 */
void expression(int level)
{
    // expressions have various format.
    // but majorly can be divided into two parts: unit and operator
    // for example `(char) *a[10] = (int *) func(b > 0 ? 10 : 20);
    // `a[10]` is an unit while `*` is an operator.
    // `func(...)` in total is an unit.
    // so we should first parse those unit and unary operators
    // and then the binary ones
    //
    // also the expression can be in the following types:
    //
    // 1. unit_unary ::= unit | unit unary_op | unary_op unit
    // 2. expr ::= unit_unary (bin_op unit_unary ...)

    // unit_unary()

    int *id;
    int tmp;
    int *addr;
    if (!token)
    {
        printf("%d: unexpected token EOF of expression\n", line);
        exit(-1);
    }
    if (token == Num)
    {
        match(Num);

        // emit code
        *++text = IMM;
        *++text = token_val;
        expr_type = INT;
    }
    else if (token == '"')
    {
        // emit code
        *++text = IMM;
        *++text = token_val;

        match('"');
        // store the rest strings
        while (token == '"')
        {
            match('"');
        }

        // append the end of string character '\0', all the data are default
        // to 0, so just move data one position forward.
        // 设置指针，data区域的指针指向字符串，与操作不太懂
        data = (char *)(((int)data + sizeof(int)) & (-sizeof(int)));
        expr_type = PTR;
    }
    else if (token == Sizeof)
    {
        // sizeof is actually an unary operator
        // now only `sizeof(int)`, `sizeof(char)` and `sizeof(*...)` are
        // supported.
        match(Sizeof);
        match('(');
        // 表达式的类型及表达式的返回类型
        expr_type = INT;

        if (token == Int)
        {
            match(Int);
        }
        else if (token == Char)
        {
            match(Char);
            expr_type = CHAR;
        }

        while (token == Mul)
        {
            match(Mul);
            expr_type = expr_type + PTR;
        }

        match(')');

        // emit code
        *++text = IMM;
        // 指针类型和int类型都是放回一个整型（4字节）当是char是1字节
        *++text = (expr_type == CHAR) ? sizeof(char) : sizeof(int);

        expr_type = INT;
    }
    else if (token == Id)
    {
        // there are several type when occurs to Id  出现Id时有几种类型
        // but this is unit, so it can only be
        // 1. function call
        // 2. Enum variable
        // 3. global/local variable
        match(Id);

        id = current_id;

        // 参数处理
        if (token == '(')
        {
            // function call
            match('(');

            // ①中注意我们是顺序将参数入栈，这和第三章：虚拟机中讲解的指令是对应的。与之不同，标准 C 是逆序将参数入栈的。
            // pass in arguments
            tmp = 0; // number of arguments
            while (token != ')')
            {
                // 赋值表达式将数值放入ax寄存器中 后续我们将数值压入栈中
                expression(Assign);

                *++text = PUSH;
                tmp++;

                if (token == ',')
                {
                    match(',');
                }
            }
            match(')');

            // 判断是自定义函数还是系统函数
            // ②中判断函数的类型，同样在第三章：“虚拟机”中我们介绍过内置函数的支持，如 printf, read, malloc 等等。内置函数有对应的汇编指令，而普通的函数则编译成 CALL <addr> 的形式。
            // emit code
            if (id[Class] == Sys)
            {
                // system functions
                // id[Value]保存的是函数的调用地址
                // 但是这里不用加一个无条件跳转指令之类的码？
                *++text = id[Value];
            }
            else if (id[Class] == Fun)
            {
                // function call
                *++text = CALL;
                *++text = id[Value];
            }
            else
            {
                printf("%d: bad function call\n", line);
                exit(-1);
            }

            // ③用于清除入栈的参数。因为我们不在乎出栈的值，所以直接修改栈指针的大小即可。
            // clean the stack for arguments
            if (tmp > 0)
            {
                // stack中sp指针上调
                *++text = ADJ;
                *++text = tmp;
            }
            // 表达式的类型为函数的放回类型
            expr_type = id[Type];
        }
        else if (id[Class] == Num)
        {
            // ④当该标识符是全局定义的枚举类型时，直接将对应的值用 IMM 指令存入 AX 即可。  枚举变量类型必定为int 不用犹豫
            // enum variable
            *++text = IMM;
            *++text = id[Value];
            expr_type = INT;
        }
        else
        {
            // ⑤则是用于加载变量的值，如果是局部变量则采用与 bp 指针相对位置的形式（参见第 7章函数定义）。而如果是全局变量则用 IMM 加载变量的地址。
            // variable
            // 局部变量处理
            if (id[Class] == Loc)
            {
                // 取栈顶的值 	LEA：load address for arguments.
                *++text = LEA;
                // bp的值加偏差 id[value]存放第几个参数 右到左
                *++text = index_of_bp - id[Value];
            }
            else if (id[Class] == Glo)
            {
                // 将num（param）放到ax,全局变量将全局变量的参数地址加载到ax中
                *++text = IMM;
                *++text = id[Value];
            }
            else
            {
                printf("%d: undefined variable\n", line);
                exit(-1);
            }

            // ⑥无论是全局还是局部变量，最终都根据它们的类型用 LC 或 LI 指令加载对应的值。
            //  emit code, default behaviour is to load the value of the
            //  address which is stored in `ax`
            expr_type = id[Type];
            *++text = (expr_type == Char) ? LC : LI;
        }
    }
    else if (token == '(')
    {
        // cast or parenthesis
        // 前面的if判断已经处理了函数调用的括号，所以这里可以放心大胆的判断为强制类型转换
        match('(');
        if (token == Int || token == Char)
        {
            tmp = (token == Char) ? CHAR : INT; // cast type
            match(token);
            // 是否是强转成了指针类型
            while (token == Mul)
            {
                match(Mul);
                tmp = tmp + PTR;
            }

            match(')');

            expression(Inc); // cast has precedence as Inc(++)

            expr_type = tmp;
        }
        else
        {
            // normal parenthesis
            // 仅支持char与int的或指针的强转，如果'（'后没有接char或int 则可能是表达式了
            expression(Assign);
            match(')');
        }
    }
    else if (token == Mul)
    {
        // dereference *<addr>
        match(Mul);
        // 指针引用地址引用同++有相同的优先级
        expression(Inc); // dereference has the same precedence as Inc(++)

        // 表达式的类型必须是一个指针 是的话减去指针类型 回到前一层地址引用或基类型
        if (expr_type >= PTR)
        {
            expr_type = expr_type - PTR;
        }
        else
        {
            printf("%d: bad dereference\n", line);
            exit(-1);
        }
        // 加载前一层的指针值或基类型的值
        *++text = (expr_type == CHAR) ? LC : LI;
    }
    else if (token == And)
    {
        // get the address of
        match(And);
        expression(Inc); // get the address of
        if (*text == LC || *text == LI)
        {
            text--;
        }
        else
        {
            printf("%d: bad address of\n", line);
            exit(-1);
        }

        expr_type = expr_type + PTR;
    }
    else if (token == '!')
    {
        // not 取反
        match('!');
        // 不是很懂 一元运算符的++如果在！后面需要先++在！，但--呢！只判断jj不判断--？？
        expression(Inc);

        // emit code, use <expr> == 0
        // 将目标值放入栈中 ax放0 进行eq操作 等于的话说明！对象为0，结果为1 否者不等 结果为0
        *++text = PUSH;
        *++text = IMM;
        *++text = 0;
        *++text = EQ;

        expr_type = INT;
    }
    else if (token == '~')
    {
        // bitwise not
        match('~');
        // 不是很懂 一元运算符的++如果在！后面需要先++在！，但--呢！只判断jj不判断--？？
        expression(Inc);

        // emit code, use <expr> XOR -1
        // 异或的是-1及0xffff
        *++text = PUSH;
        *++text = IMM;
        *++text = -1;
        *++text = XOR;

        expr_type = INT;
    }
    else if (token == Add)
    {
        // +var, do nothing
        match(Add);
        expression(Inc);

        expr_type = INT;
    }
    else if (token == Sub)
    {
        // -var
        match(Sub);

        if (token == Num)
        {
            *++text = IMM;
            *++text = -token_val;
            match(Num);
        }
        else
        {
            // 不是一个数字，可能是一个表达式什么的话，如果是一个表达式的话就生成乘以（-1）的汇编代码
            *++text = IMM;
            *++text = -1;
            *++text = PUSH;
            expression(Inc);
            *++text = MUL;
        }

        expr_type = INT;
    }
    else if (token == Inc || token == Dec)
    {
        tmp = token;
        match(token);
        expression(Inc);
        // ①对应的汇编代码也比较直观，只是在实现 ++p时，我们要使用变量 p 的地址两次，所以我们需要先 PUSH
        if (*text == LC)
        {
            // LC加载具体的数值，我们不加载，我们将ax（变量的地址）进行压栈
            // push先将变量p的地址进行保存
            *text = PUSH; // to duplicate the address
            *++text = LC;
        }
        else if (*text == LI)
        {
            *text = PUSH;
            *++text = LI;
        }
        else
        {
            printf("%d: bad lvalue of pre-increment\n", line);
            exit(-1);
        }
        // 将变量p的值取到ax中后压入栈中
        // 将下一值放ax中
        *++text = PUSH;
        *++text = IMM;
        // ②因为自增自减操作还需要处理是指针的情形 char在int的前面，及char比较小，不是char的话无论是int还是指针，如果是指针的话 ++ 就是加上指针的地址4（指向指向下一地址） 指针占用一个整型的大小 如果类型小于int或char 就是加1（数值上的加1）
        // 对应IMM的立即数 4 或者1
        *++text = (expr_type > PTR) ? sizeof(int) : sizeof(char);
        // 真正的实现+ 或-
        *++text = (tmp == Inc) ? ADD : SUB;
        // 栈
        // 2. 变量的值（这个栈顶将参与ADD或SUB运算）
        // 1. 变量的地址
        // 所以这里用到的SC及SI的栈顶元素是地址没有错误
        *++text = (expr_type == CHAR) ? SC : SI;
    }
    else
    {
        printf("%d: bad expression\n", line);
        exit(-1);
    }

    // binary operator and postfix operators.
    while (token >= level)
    {
        // parse token for binary operator and postfix operator
        tmp = expr_type;
        if (token == Assign)
        {
            // var = expr;
            // 前面是变量 的取值
            // IMM <addr>
            // LC/LI 取消这条指令 将变量的地址压栈
            match(Assign);
            if (*text == LC || *text == LI)
            {
                *text = PUSH; // save the lvalue's pointer
            }
            else
            {
                printf("%d: bad lvalue in assignment\n", line);
                exit(-1);
            }
            // 继续解析表达式 参数Assign为栈顶操作符的等级Assign最低
            expression(Assign); // 将结果放在ax中
                                // 临时变量值
            // 将变量的赋值转换为 SC or SI：ax中数据以字符放指定地址，栈顶放目标地址
            expr_type = tmp;
            *++text = (expr_type == CHAR) ? SC : SI;
        }
        else if (token == Cond)
        {
            // expr ? a : b;
            match(Cond);
            *++text = JZ;
            addr = ++text;
            expression(Assign);
            if (token == ':')
            {
                match(':');
            }
            else
            {
                printf("%d: missing colon in conditional\n", line);
                exit(-1);
            }
            *addr = (int)(text + 3);
            *++text = JMP;
            addr = ++text;
            expression(Cond);
            *addr = (int)(text + 1);
        }
        else if (token == Lor)
        {
            // logic or
            match(Lor);
            // true跳转
            *++text = JNZ;
            // addr记录expr1为true短路后的跳转地址
            addr = ++text;
            // 解析表达式 Lan栈顶等级
            expression(Lan);
            // 回填addr的地址为当前text的地址+1，下一地址
            // int类型
            *addr = (int)(text + 1);
            expr_type = INT;
        }
        else if (token == Lan)
        {
            // logic and
            match(Lan);
            *++text = JZ;
            // expr1为false的地址，需要回填
            addr = ++text;
            expression(Or);
            // 回填
            *addr = (int)(text + 1);
            expr_type = INT;
        }
        else if (token == Or)
        {
            // bitwise or
            match(Or);
            *++text = PUSH;
            expression(Xor);
            *++text = OR;
            expr_type = INT;
        }
        else if (token == Xor)
        {
            // bitwise xor
            match(Xor);
            *++text = PUSH;
            expression(And);
            *++text = XOR;
            expr_type = INT;
        }
        else if (token == And)
        {
            // bitwise and
            match(And);
            *++text = PUSH;
            expression(Eq);
            *++text = AND;
            expr_type = INT;
        }
        else if (token == Eq)
        {
            // equal ==
            match(Eq);
            *++text = PUSH;
            expression(Ne);
            *++text = EQ;
            expr_type = INT;
        }
        else if (token == Ne)
        {
            // not equal !=
            match(Ne);
            *++text = PUSH;
            expression(Lt);
            *++text = NE;
            expr_type = INT;
        }
        else if (token == Lt)
        {
            // less than
            match(Lt);
            *++text = PUSH;
            expression(Shl);
            *++text = LT;
            expr_type = INT;
        }
        else if (token == Gt)
        {
            // greater than
            match(Gt);
            *++text = PUSH;
            expression(Shl);
            *++text = GT;
            expr_type = INT;
        }
        else if (token == Le)
        {
            // less than or equal to
            match(Le);
            *++text = PUSH;
            expression(Shl);
            *++text = LE;
            expr_type = INT;
        }
        else if (token == Ge)
        {
            // greater than or equal to
            match(Ge);
            *++text = PUSH;
            expression(Shl);
            *++text = GE;
            expr_type = INT;
        }
        else if (token == Shl)
        {
            // shift left
            match(Shl);
            *++text = PUSH;
            expression(Add);
            *++text = SHL;
            expr_type = INT;
        }
        else if (token == Shr)
        {
            // shift right
            match(Shr);
            *++text = PUSH;
            expression(Add);
            *++text = SHR;
            expr_type = INT;
        }

        else if (token == Add)
        {
            // add
            match(Add);
            *++text = PUSH;
            // 为何解析表达式的时候栈顶元素是乘
            expression(Mul);

            expr_type = tmp;
            if (expr_type > PTR)
            {
                // pointer type, and not `char *`
                *++text = PUSH;
                *++text = IMM;
                *++text = sizeof(int);
                *++text = MUL;
            }
            *++text = ADD;
        }
        else if (token == Sub)
        {
            // sub
            match(Sub);
            *++text = PUSH;
            expression(Mul);
            if (tmp > PTR && tmp == expr_type)
            {
                // pointer subtraction
                *++text = SUB;
                *++text = PUSH;
                *++text = IMM;
                *++text = sizeof(int);
                *++text = DIV;
                expr_type = INT;
            }
            else if (tmp > PTR)
            {
                // pointer movement
                *++text = PUSH;
                *++text = IMM;
                *++text = sizeof(int);
                *++text = MUL;
                *++text = SUB;
                expr_type = tmp;
            }
            else
            {
                // numeral subtraction
                *++text = SUB;
                expr_type = tmp;
            }
        }
        else if (token == Mul)
        {
            // multiply
            match(Mul);
            *++text = PUSH;
            expression(Inc);
            *++text = MUL;
            expr_type = tmp;
        }
        else if (token == Div)
        {
            // divide
            match(Div);
            *++text = PUSH;
            expression(Inc);
            *++text = DIV;
            expr_type = tmp;
        }
        else if (token == Mod)
        {
            // Modulo
            match(Mod);
            *++text = PUSH;
            expression(Inc);
            *++text = MOD;
            expr_type = tmp;
        }
        else if (token == Inc || token == Dec)
        {
            // postfix inc(++) and dec(--)
            // we will increase the value to the variable and decrease it
            // on `ax` to get its original value.
            if (*text == LI)
            {
                *text = PUSH;
                *++text = LI;
            }
            else if (*text == LC)
            {
                *text = PUSH;
                *++text = LC;
            }
            else
            {
                printf("%d: bad value in increment\n", line);
                exit(-1);
            }

            // 后缀形式 生成汇编代码
            *++text = PUSH;
            *++text = IMM;
            *++text = (expr_type > PTR) ? sizeof(int) : sizeof(char);
            *++text = (token == Inc) ? ADD : SUB;
            *++text = (expr_type == CHAR) ? SC : SI;
            // 实际上到这里完成了对ax的增，及减 ax为增加后的值 记完成了a++ 记a--的++或--操作但是我们要用的是为++或--前的值 后面的汇编代码执行逆操作 回到之前好吧
            *++text = PUSH;                                           // 压入后
            *++text = IMM;                                            // 执行相反的增/减操作
            *++text = (expr_type > PTR) ? sizeof(int) : sizeof(char); //
            *++text = (token == Inc) ? SUB : ADD;                     //
            match(token);
        }
        else if (token == Brak)
        {
            // array access var[xx]
            match(Brak);
            // 这里的push将var的地址进行了压入
            *++text = PUSH;
            // 解析中括号内的表达式
            expression(Assign);
            match(']');

            // 如果是指针
            if (tmp > PTR)
            {
                // pointer, `not char *`
                // 对值进行乘法操作
                // ax放前面解析中括号内容的值val，现在压入val到栈 计算偏移量
                *++text = PUSH;
                *++text = IMM;
                *++text = sizeof(int);
                *++text = MUL;
            }
            // 不是指针错误
            else if (tmp < PTR)
            {
                printf("%d: pointer type expected\n", line);
                exit(-1);
            }
            // 表达式值放回前一类型
            expr_type = tmp - PTR;
            // 执行ADD操作 指针加偏移量 后取值
            *++text = ADD;
            *++text = (expr_type == CHAR) ? LC : LI;
        }
        else
        {
            printf("%d: compiler error, token = %d\n", line, token);
            exit(-1);
        }
    }
}

/**
 * @brief 语法分析阶段
 *
 * @return * void
 */
void program()
{
    // get next token
    next();
    while (token > 0)
    {
        global_declaration();
    }
}

/**
 * @brief  虚拟机的入口，用于解释目标代码
 *
 * @return * int
 */
int eval()
{
    puts("test is ok!\n");
    // 定义操作指令及中间变量
    int op, *tmp;
    // 指令集判断有点长后续考虑修改为switch-case吧
    while (1)
    {
        op = *pc;
        pc++;
        switch (op)
        {
        case IMM:
            ax = *pc++;
            // load immediate value to ax
            break;
        case LC:
            ax = *(char *)ax;
            // load character to ax, address in ax
            break;
        case LI:
            ax = *(int *)ax;
            // load integer to ax, address in ax
            break;
        case SC:
            ax = *(char *)*sp++ = ax;
            // save character to address, value in ax, address on stack
            break;
        case SI:
            *(int *)*sp++ = ax;
            // save integer to address, value in ax, address on stack
            break;
        case PUSH:
            *--sp = ax;
            // push the value of ax onto the stack
            break;
        case JMP:
            pc = (int *)*pc;
            // jump to the address
            break;
        case JZ:
            pc = ax ? pc + 1 : (int *)*pc;
            // jump if ax is zero
            break;
        case JNZ:
            pc = ax ? (int *)*pc : pc + 1;
            // jump if ax is not zero
            break;
        case CALL:
            *--sp = (int)(pc + 1);
            pc = (int *)*pc;
            // call subroutine
            break;
        case ENT:
            *--sp = (int)bp;
            bp = sp;
            sp = sp - *pc++;
            // make new stack frame
            break;
        case ADJ:
            sp = sp + *pc++;
            // add esp, <size>
            break;
        case LEV:
            sp = bp;
            bp = (int *)*sp++;
            pc = (int *)*sp++;
            // restore call frame and PC
            break;
        case LEA:
            ax = (int)(bp + *pc++);
            // load address for arguments.
            break;
        case OR:
            ax = (*sp) | ax;
            sp++;
            break;
        case XOR:
            ax = *sp++ ^ ax;
            break;
        case AND:
            ax = *sp++ & ax;
            break;
        case EQ:
            ax = *sp++ == ax;
            break;
        case NE:
            ax = *sp++ != ax;
            break;
        case LT:
            ax = *sp++ < ax;
            break;
        case LE:
            ax = *sp++ <= ax;
            break;
        case GT:
            ax = *sp++ > ax;
            break;
        case GE:
            ax = *sp++ >= ax;
            break;
        case SHL:
            ax = *sp++ << ax;
            break;
        case SHR:
            ax = *sp++ >> ax;
            break;
        case ADD:
            ax = *sp++ + ax;
            break;
        case SUB:
            ax = *sp++ - ax;
            break;
        case MUL:
            ax = *sp++ * ax;
            break;
        case DIV:
            ax = *sp++ / ax;
            break;
        case MOD:
            ax = *sp++ % ax;
            break;
        case EXIT:
            printf("exit(%d)", *sp);
            return *sp;
            break;
        case OPEN:
            ax = open((char *)sp[1], sp[0]);
            break;
        case CLOS:
            ax = close(*sp);
            break;
        case READ:
            ax = read(sp[2], (char *)sp[1], *sp);
            break;
        case PRTF:
            
            tmp = sp + pc[1];
            ax = printf((char *)tmp[-1]);
            // tmp[-2], tmp[-3], tmp[-4], tmp[-5], tmp[-6]);
            printf("%d", &sp);
            printf("%d", &tmp[-1]);
            break;
        case MALC:
            ax = (int)malloc(*sp);
            break;
        case MSET:
            ax = (int)memset((char *)sp[2], sp[1], *sp);
            break;
        case MCMP:
            ax = memcmp((char *)sp[2], (char *)sp[1], *sp);
            break;
        default:
            printf("unknown instruction:%d\n", op);
            return -1;
            break;
        }
    }

    return 0;
}

int main(int argc, char **argv)
{
    // i为读取的文件返回值，fd为文件描述符
    int i, fd;
    int *tmp;

    argc--;
    // argv[0] 为本文件名
    argv++;
    // 源代码缓冲区 256k
    poolSize = 4 * 1024;
    // 设置当前行号为1
    line = 1;

    // 为虚拟机分配内存
    if (!(text = old_text = malloc(poolSize)))
    {
        printf("could not malloc(%d) for text area\n", poolSize);
        return -1;
    }
    data = (char *)(text + (1 * 1024) / 4);
    stack = (int *)(text + (2 * 1024) / 4);
    symbols = (int *)(text + (3 * 1024) / 4);
    // if (!(data = malloc(poolSize)))
    // {
    //     printf("could not malloc(%d) for data area\n", poolSize);
    //     return -1;
    // }
    // if (!(stack = malloc(poolSize)))
    // {
    //     printf("could not malloc(%d) for stack area\n", poolSize);
    //     return -1;
    // }
    // // 为符号表申请内存空间
    // if (!(symbols = malloc(poolSize)))
    // {
    //     printf("could not malloc(%d) for symbol table\n", poolSize);
    //     return -1;
    // }

    // 初始化内存为零0
    memset(text, 0, poolSize);
    // memset(data, 0, poolSize);
    // memset(stack, 0, poolSize);
    // memset(symbols, 0, poolSize);
    // 初始化虚拟机的寄存器
    // bp sp同时指向栈顶
    bp = sp = (int *)((int)stack + (poolSize) / 4 / 4);
    ax = 0;
    // pc=.. 理论上pc指向main函数哦！！

    // // test code

    // printf("now start test!");
    // i = 0;
    // text[i++] = IMM;
    // text[i++] = 10;
    // text[i++] = PUSH; // ax 压栈
    // text[i++] = IMM;  // 20 到 ax
    // text[i++] = 20;
    // text[i++] = ADD;  // 栈顶与ax相加
    // text[i++] = PUSH; // 将ax压入栈
    // text[i++] = EXIT; // 退出程序  此时放回栈顶数值
    // pc = text;
    // printf("now end test!");

    // test code

    // // test Lexical analyzer
    // // test Lexical analyzer
    // // 关键字及内置函数，在语法解析调用前先填入符号表中
    src = "char else enum if int return sizeof while "
          "open read close printf malloc memset memcmp exit void main";

    // add keywords to symbol table
    // i等于0 同理
    i = Char; // i=134 Char定义来之emun
    while (i <= While)
    {
        // 此时next函数处理的是src（也即是前面定义的的关键字及内置函数字符串）
        // 现在处理关键字
        next();
        current_id[Token] = i++;
    }
    // 内置函数
    // add library to symbol table
    i = OPEN;
    while (i <= EXIT)
    {
        // 现在处理内置函数
        // 并进行赋值，赋值为系统调用
        next();
        current_id[Class] = Sys;
        current_id[Type] = INT;
        current_id[Value] = i++;
    }

    next();
    current_id[Token] = Char; // handle void type
    next();
    idmain = current_id; // keep track of main

    // printf("will interpreter file!\n");
    puts("\n");
    // printf("**%s**\n", argv[1]);
    // 打开文件
    // if ((fd = open(*argv[2], 0)) < 0)
    if ((fd = open(argv[1], 0)) < 0)
    {
        printf("could not open(%s)\n", *argv);
        return -1;
    }

    // 读取源文件
    if (!(src = old_src = malloc(poolSize)))
    {
        printf("could not malloc(%d) for source area\n", poolSize);
        return -1;
    }

    // 读取源文件最大读取256k（poolSize）的大小
    if ((i = read(fd, src, poolSize - 1)) <= 0)
    {
        printf("read() returned %d\n", i);
        return -1;
    }

    // 源文件流追加结束标志并关闭文件
    src[i] = 0;
    close(fd);

    printf("printf the file!\n");
    puts(src);
    // for (int i = 0; *src!='\0'; i++)
    // {
    //     printf("%c", *(src[0]));
    // }

    // 语法分析（语法分析会调用词法分析的）
    program();

    // idmain[Value]   实际上取到main函数得地址 强制转换成（int *）给pc 避免了pc没有初始化得问题
    if (!(pc = (int *)idmain[Value]))
    {
        printf("main() not defined\n");
        return -1;
    }

    // setup stack 设置栈
    // 栈指针指向我们申请的stack的栈顶位置
    sp = (int *)((int)stack + poolSize);
    *--sp = EXIT; // call exit if main returns
    *--sp = PUSH;
    tmp = sp;
    // 参数个数记值得指针		tmp我也不知道是什么
    *--sp = argc;
    *--sp = (int)argv;
    *--sp = (int)tmp;

    // 解释目标代码
    return eval();
}
